package com.example.summary.dui;

import com.alibaba.fastjson.JSON;

import java.io.*;
import java.util.*;

/**
 * Created by wzn on 2019/4/25.
 */
public class Dui {

//    public static void main(String[] args) {
//        int[] dui = new int[]{0, 62, 88, 58, 47, 62, 35, 73, 51, 99, 37, 63};
//        daDingDui(dui);
//        System.out.println(JSON.toJSONString(dui));
//        xiaoDingDui(dui);
//        System.out.println(JSON.toJSONString(dui));
//        xiaoDingDuiPai(dui);
//        System.out.println(JSON.toJSONString(dui));
//    }

    private static void daDingDuiPai(int[] dui) {
        for (int x = dui.length - 1; x > 0; x--) {
            swap(dui, 1, x);
            daDingDuiHua(dui, x - 1, 1);
        }
    }

    public static void daDingDui(int[] dui) {
        for (int x = (dui.length - 1) / 2; x > 0; x--) {
            daDingDuiHua(dui, dui.length - 1, x);
        }
    }

    private static void daDingDuiHua(int[] dui, int length, int x) {
        while (true) {
            int max = x;

            if (x * 2 <= length && dui[x] < dui[x * 2]) {
                max = x * 2;
            }

            if (x * 2 + 1 <= length && dui[max] < dui[x * 2 + 1]) {
                max = x * 2 + 1;
            }

            if (max == x) {
                break;
            }

            swap(dui, x, max);

            x = max;
        }
    }

    private static void xiaoDingDuiPai(int[] dui) {
        for (int x = dui.length - 1; x > 0; x--) {
            swap(dui, 1, x);
            xiaoDingDuiHua(dui, x - 1, 1);
        }
    }

    public static void xiaoDingDui(int[] dui) {
        for (int x = (dui.length - 1) / 2; x > 0; x--) {
            xiaoDingDuiHua(dui, dui.length - 1, x);
        }
    }

    private static void xiaoDingDuiHua(int[] dui, int length, int x) {
        while (true) {
            int max = x;

            if (x * 2 <= length && dui[x] > dui[x * 2]) {
                max = x * 2;
            }

            if (x * 2 + 1 <= length && dui[max] > dui[x * 2 + 1]) {
                max = x * 2 + 1;
            }

            if (max == x) {
                break;
            }

            swap(dui, x, max);

            x = max;
        }
    }

    private static void swap(int[] dui, int start, int end) {
        int temp = dui[end];
        dui[end] = dui[start];
        dui[start] = temp;
    }


//    public static void main(String[] args) {
//        /**
//         * init
//         */
//        int[][] suzhu = new int[5][101];
//        for (int x = 0; x < 5; x++) {
//            suzhu[x][0] = -1;
//        }
//
//        for (int x = 0; x < 5; x++) {
//            for (int y = 1; y <= 100; y++) {
//                suzhu[x][y] = (int) (Math.random() * 100);
//            }
//        }
//
//        for (int x = 0; x < 5; x++) {
//            daDingDui(suzhu[x]);
//            daDingDuiPai(suzhu[x]);
//            System.out.println(JSON.toJSONString(suzhu[x]));
//        }
//
//        Integer[] result = heBinYouXu(suzhu);
//
//        System.out.println(JSON.toJSONString(result));
//    }

    static class Node {
        int value;
        int x;
        int y;

        public Node(int value, int x, int y) {
            this.value = value;
            this.x = x;
            this.y = y;
        }
    }

    private static Integer[] heBinYouXu(int[][] suzhu) {
        /**
         * begin
         */

        //最后的输出结果
        int resultSize = 0;
        Integer[] result = new Integer[500];

        Node[] xiaoDingDui = new Node[6];
        int xiaoDingDuiSize = xiaoDingDui.length;

        xiaoDingDui[0] = null;
        xiaoDingDui[1] = new Node(suzhu[0][1], 0, 1);
        xiaoDingDui[2] = new Node(suzhu[1][1], 1, 1);
        xiaoDingDui[3] = new Node(suzhu[2][1], 2, 1);
        xiaoDingDui[4] = new Node(suzhu[3][1], 3, 1);
        xiaoDingDui[5] = new Node(suzhu[4][1], 4, 1);

        while (resultSize < result.length) {
            /**
             * 先堆化
             */
            xiaoDingDui(xiaoDingDui);

            /**
             * 取值
             */
            Node duiDing = xiaoDingDui[1];
            result[resultSize] = duiDing.value;

            /**
             * 替换堆顶，如果已经有的数据达到了100
             */
            if (duiDing.y + 1 >= suzhu[duiDing.x].length) {
                swap(xiaoDingDui, 1, --xiaoDingDuiSize);
                /**
                 * 如果不删除，会导致，已经入大集合队列的数据会重新堆排
                 */
                xiaoDingDui[xiaoDingDuiSize] = null;
            } else {
                xiaoDingDui[1] = new Node(suzhu[duiDing.x][duiDing.y + 1], duiDing.x, duiDing.y + 1);
            }

            resultSize++;
        }

        return result;
    }

    public static void xiaoDingDui(Node[] dui) {
        for (int x = (dui.length - 1) / 2; x > 0; x--) {
            xiaoDingDuiHua(dui, dui.length - 1, x);
        }
    }

    private static void xiaoDingDuiHua(Node[] dui, int length, int x) {
        while (true) {
            int max = x;

            if (x * 2 <= length && dui[x * 2] != null && dui[x].value > dui[x * 2].value) {
                max = x * 2;
            }

            if (x * 2 + 1 <= length && dui[x * 2 + 1] != null && dui[max].value > dui[x * 2 + 1].value) {
                max = x * 2 + 1;
            }

            if (max == x) {
                break;
            }

            swap(dui, x, max);

            x = max;
        }
    }

    private static void swap(Node[] dui, int start, int end) {
        Node temp = dui[end];
        dui[end] = dui[start];
        dui[start] = temp;
    }


    static Map<Integer, LiuOut> liuMap = new HashMap<>();
    static List<String> nameList = Arrays.asList("test0", "test1", "test2", "test3", "test4");

    static class TopNode {
        private String name;
        private int size;

        public TopNode(String name, int size) {
            this.name = name;
            this.size = size;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }
    }

    /**
     * 100万关键字，取出现频率前五的关键字
     *
     * @param args
     */
    public static void main(String[] args) {
        String name = "test";
        String path = "F:\\summary\\src\\main\\resources\\";
        TopNode[] topNodes = new TopNode[6];

//        try {
//            writeFile02(path,name);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }


//
//        try {

//            readFile(path, name);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//
        nameList.forEach(action -> {

            Map<String, Integer> everySize = new HashMap<>();

            try {
                LiuIn liuIn = readFileEvery(path, action);

                String s = "";
                while ((s = liuIn.br.readLine()) != null) {
                    Integer integer = everySize.get(s);
                    if (null == integer) {
                        integer = 0;
                    }
                    everySize.put(s, ++integer);
                }

                liuIn.br.close();
                liuIn.isr.close();
                liuIn.fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            final int[] x = {1};
            everySize.forEach((key, value) -> {
                /**
                 * 如果值大于小顶堆的值，就替换小顶堆，然后小顶堆堆化
                 */
                if (x[0] <= 5 && null == topNodes[x[0]]) {
                    topNodes[x[0]] = new TopNode(key, value);
                }

                if (x[0] > 5 && value > topNodes[1].size) {
                    topNodes[1] = new TopNode(key, value);
                }

                xiaoDingDui(topNodes);
                x[0]++;
            });
            System.out.println(1);
        });
        System.out.println(JSON.toJSONString(topNodes));
    }

    static class LiuOut {
        FileOutputStream fos;
        OutputStreamWriter osw;
        BufferedWriter bw;

        public LiuOut(FileOutputStream fos, OutputStreamWriter osw, BufferedWriter bw) {
            this.fos = fos;
            this.osw = osw;
            this.bw = bw;
        }
    }

    static class LiuIn {
        FileInputStream fis;
        InputStreamReader isr;
        BufferedReader br;

        public LiuIn(FileInputStream fis, InputStreamReader isr, BufferedReader br) {
            this.fis = fis;
            this.isr = isr;
            this.br = br;
        }
    }

    /**
     * 一行一行读取文件，解决读取中文字符时出现乱码
     * <p>
     * 流的关闭顺序：先打开的后关，后打开的先关，
     * 否则有可能出现java.io.IOException: Stream closed异常
     *
     * @throws IOException
     */
    public static LiuIn readFileEvery(String path, String name) throws IOException {
        FileInputStream fis = new FileInputStream(path + name + ".txt");
        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        return new LiuIn(fis, isr, br);
    }

    /**
     * 一行一行读取文件，解决读取中文字符时出现乱码
     * <p>
     * 流的关闭顺序：先打开的后关，后打开的先关，
     * 否则有可能出现java.io.IOException: Stream closed异常
     *
     * @throws IOException
     */
    public static void readFile(String path, String name) throws IOException {
        FileInputStream fis = new FileInputStream(path + name + ".txt");
        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        //简写如下
        //BufferedReader br = new BufferedReader(new InputStreamReader(
        //        new FileInputStream("E:/phsftp/evdokey/evdokey_201103221556.txt"), "UTF-8"));
        String line = "";
        while ((line = br.readLine()) != null) {
            int x = line.hashCode() % 5;
            LiuOut liu = liuMap.get(x);
            if (null == liu) {
                liu = writeFile(path, name, line);
                liuMap.put(x, liu);
            }
            liu.bw.write(line + "\n");
        }

        liuMap.forEach((x, y) -> {
            try {
                y.bw.close();
                y.osw.close();
                y.fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        br.close();
        isr.close();
        fis.close();
    }

    /**
     * 一行一行写入文件，解决写入中文字符时出现乱码
     * <p>
     * 流的关闭顺序：先打开的后关，后打开的先关，
     * 否则有可能出现java.io.IOException: Stream closed异常
     *
     * @throws IOException
     */
    public static LiuOut writeFile(String path, String name, String value) throws IOException {
        int x = value.hashCode() % 5;

        //写入中文字符时解决中文乱码问题
        FileOutputStream fos = new FileOutputStream(new File(path + name + x + ".txt"));
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw);
        return new LiuOut(fos, osw, bw);
    }

    /**
     * 一行一行写入文件，解决写入中文字符时出现乱码
     * <p>
     * 流的关闭顺序：先打开的后关，后打开的先关，
     * 否则有可能出现java.io.IOException: Stream closed异常
     *
     * @throws IOException
     */
    public static void writeFile02(String patd, String name) throws IOException {

        //写入中文字符时解决中文乱码问题
        FileOutputStream fos = new FileOutputStream(new File(patd + name + ".txt"));
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw);
        //简写如下：
        //BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
        //        new FileOutputStream(new File("E:/phsftp/evdokey/evdokey_201103221556.txt")), "UTF-8"));
        for (int i = 0; i < 1000000; i++) {
            bw.write("A" + (int) (Math.random() * 100) + "\n");
        }

        //注意关闭的先后顺序，先打开的后关闭，后打开的先关闭
        bw.close();
        osw.close();
        fos.close();
    }

    public static void xiaoDingDui(TopNode[] dui) {
        for (int x = (dui.length - 1) / 2; x > 0; x--) {
            xiaoDingDuiHua(dui, dui.length - 1, x);
        }
    }

    private static void xiaoDingDuiHua(TopNode[] dui, int length, int x) {
        while (true) {
            int max = x;

            if (x * 2 <= length && dui[x * 2] != null && dui[x].size > dui[x * 2].size) {
                max = x * 2;
            }

            if (x * 2 + 1 <= length && dui[x * 2 + 1] != null && dui[max].size > dui[x * 2 + 1].size) {
                max = x * 2 + 1;
            }

            if (max == x) {
                break;
            }

            swap(dui, x, max);

            x = max;
        }
    }

    private static void swap(TopNode[] dui, int start, int end) {
        TopNode temp = dui[end];
        dui[end] = dui[start];
        dui[start] = temp;
    }
}
